﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Globalization;
using Newtonsoft.Json.Linq;
using FBEntities.FBObjects.User;
using FBEntities.FBObjects;
using System.IO;
using System.Xml.Linq;
using System.Xml;
using System.Threading;

namespace FBEntities
{
    public class FBDataSource
    {
        public FBPerson Me { get; set; }

        public FBDataSource(string key)
        {
            FBParseUtilities.authKey = key;

            Me = FBCache.GetMe();
            FBCache.SaveCache();
        }
    }

    public static class FBCache
    {
        private static string meId = "person-";
        public static bool BlockNextCache;
        private static XDocument fbData;
        internal static XDocument FbData
        {
            get
            {
                if (fbData == null)
                {
                    try
                    {
                        fbData = XDocument.Load(path);
                    }
                    catch (Exception)
                    {
                        fbData = new XDocument(
                            new XDeclaration("1.0", "utf-8", "yes"),
                            new XElement("cacheData"));
                    }
                }
                return fbData;
            }
        }
        private static string path = FBParseUtilities.CurDir + "\\data.xfd";
        private static string meUrl = "https://graph.facebook.com/me?" + authKey;

        private static string authKey { get { return FBParseUtilities.authKey; } }

        private static bool canCache()
        {
            if (!File.Exists(path))
            {
                XDocument doc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("cacheData"));

                doc.Save(path);
            }

            if (BlockNextCache)
            {
                BlockNextCache = false;
                return BlockNextCache;
            }

            return true;
        }

        public static FBPerson GetMe()
        {
            if (!canCache())
            {
                JObject o = JObject.Parse(WebDownloader.DownloadJSON(meUrl));

                FBPerson pers = new FBPerson();

                pers.Parse(o);

                return pers;
            }

            var ret = GetPerson("me");
            meId += ret.id;
            return ret;
        }

        public static FBPerson GetPerson(string id)
        {
            if (id == meId)
                id = "me";

            if (canCache())
            {
                var linq = from m in FbData.Root.Descendants()
                           where m.Name == id
                           select m;

                if (linq.Count() > 0)
                {
                    var meXml = linq.First();
                    JObject o = JObject.Parse(meXml.Value);
                    FBPerson pers = new FBPerson();
                    pers.Parse(o);
                    return pers;
                }
            }

            string json = WebDownloader.DownloadJSON(meUrl);
            cache(json, id);
            JObject obj = JObject.Parse(json);

            FBPerson ret = new FBPerson();

            ret.Parse(obj);

            return ret;

        }

        private static void cache(string json, string id)
        {
            if (!canCache())
                return;

            XElement elm = null;
            if ((elm = FbData.Root.Element(id)) != null)
            {
                elm.SetValue(json);
                SaveCache();
            }
            else
                FbData.Root.Add(new XElement(id, json));
        }

        public static string GetJSON(string id, string url)
        {
            return GetJSON(id, url, true);
        }

        public static string GetJSON(string id, string url, bool saveToCache)
        {
            if (canCache())
            {
                var linq = from m in FbData.Root.Descendants()
                           where m.Name == id
                           select m;

                if (linq.Count() > 0)
                {
                    var meXml = linq.First();
                    return meXml.Value;
                }
            }

            string json = WebDownloader.DownloadJSON(url);

            if (saveToCache)
            {
                cache(json, id);
                SaveCache();
            }
            return json;
        }

        public static string GetCachedJSON(string id)
        {
            var linq = from m in FbData.Root.Descendants()
                       where m.Name == id
                       select m;

            if (linq.Count() > 0)
            {
                var meXml = linq.First();
                return meXml.Value;
            }

            return null;
        }

        public static void SaveCache()
        {
            try
            {
                FbData.Save(path);
            }
            catch (IOException e)
            {
                if (e.Message.Contains("being used by another process"))
                {
                    Thread.Sleep(300);
                    SaveCache();
                }
            }
        }
    }
}
